function fn(num){
    return num * 3
}

function* gen(){
    let res = yield fn(2)
    let res1 = yield fn(res)
    let res2 = yield fn(res1)
    return res2
}

function generatorFn(generator){
    let gen = generator.apply(this, arguments)
    return function () {
        return new Promise((resolve,reject) => {
            function go(key,arg){
                let res 
                try {
                    res = gen[key](arg)
                } catch (error) {
                   reject(error) 
                }
                let { value ,done } = res
                if(done){
                    resolve(value)
                } else {
                    go('next',value)
                }
            }

            go('next')
        })
    }
}

let fn1 = generatorFn(gen)
fn1().then(res=> {
    console.log(res)
})

function debounce(fn,await,immdiate){
    let timer = null
    return function(){
        if(timer){
            clearTimeout(timer)
        }
        if(immdiate){
            let callnow = !timer
            timer = setTimeout(()=> {
                timer = null
            },await)
            if(callnow){
                fn.apply(this) 
            }
        } else {
           
            timer = setTimeout(()=>{
                fn.apply(this)
                timer = null
            },await)
        }

    }
}

function throttle(fn,await,immdiate){
    let timer = null, time = 0
    return function () {
        if(immdiate){
            let datenow = Date.now()
            if(datenow - time > await){
                fn.apply(this)
                time = datenow
            }
        } else {
            if(!timer){
                timer = setTimeout(()=> {
                    fn.apply(this)
                    timer = null
                    setTimeout(timer)
                },await)
            }
        }
    }
}


function deepClone(obj){
    if(obj === null) return obj
    if(obj instanceof Date) return new Date(obj)
    if(obj instanceof RegExp) return new RegExp(obj)
    if(typeof obj !== 'object') return obj
    let newObj = obj  instanceof Array ? [] : {}
    for(let key in obj){
        if(obj.hasOwnProperty(key)){
            newObj[key] =  typeof obj[key]  === 'object' ? this.deepClone(obj[key])  : obj[key]
        }
    }
    return newObj
}
console.log(null == null, null === null, undefined == undefined, undefined === undefined, null == undefined, undefined === null)


Function.prototype.sx_call = function(obj, ...args){
    obj = obj || window
    let fn = Symbol()
    obj[fn] = this
    return obj[fn](...args)
}

Function.prototype.sx_apply = function(obj, args){
    obj = obj || window
    let fn = Symbol()
    obj[fn] = this
    return obj[fn](...args)
}

const testobj = {
    name: '33',
    testFn(age,sex){
        console.log(`${this.name}${age}岁了,且性别为${sex}`)
    }
}

const testobj2 = {
    name: '333332222222'
}

Function.prototype.sx_bind = function(obj, ...arg){
    obj = obj || window
    fn = Symbol()
    obj[fn] = this
    return function(...otherArgs){
        let sArg = [...arg, ...otherArgs]
        return obj[fn](...sArg)
    }
}

var result = testobj.testFn.sx_bind(testobj2)
// result(34,'男')
// result(23,'女')


class EventEmitter {
    constructor(){
        this.events = {}
    }
    on(name,fn){
        if(this.events[name]){
            this.events[name].push(fn)
        } else {
            this.events[name] = [fn]
        }
    }

    off(name, fn){
        if(this.events[name]){
            this.events[name] = this.events[name].filter(item => { return item != fn})
        }
    }

    emit(name,...rest){
        if(this.events[name]){
            this.events[name].forEach(fn => fn.apply(this, ...rest) )
        }
    }

    once(name,fn){
        function f(){
            fn()
            this.off(name,f)
        }
        this.on(name,f)
    }
}

let b = ()=> {console.log(23)}
let c = ()=> {console.log(34)}

let data = new EventEmitter()
// data.on('test',b)
// data.on('test',b)
// data.once('test1', c)

// data.emit('test')
// data.off('test', b)
// data.emit('test')
// data.emit('test1')
// data.emit('test1')


function getUrlParam(url){
    let params = {},str = ''
    if(url.indexOf('?') > -1){
        str = url.split('?')?.[1]
    }
    let arr = str.split('&')
    for(let k of arr){
        let key = k.split('=')?.[0]
        let value = k.split('=')?.[1]
        params[key] = decodeURIComponent(value)
    }
    return params
}

// console.log(getUrlParam('http://www.baidu.com?user=%E9%98%BF%E9%A3%9E&age=16'))


function setUrlParams(url, params){
    let str = ''
    for(let key in params){
        if(str){
            str = str + `&${key}=${params[key]}`
        } else {
            str = `?${key}=${params[key]}`
        }
    }
    return url + str
}

// console.log(setUrlParams('http://www.baidu.com',{user: 'xuna',age: 12}))



function all(promises){
    let result = []
    let count = 0
    return new Promise((resolve,reject) => {
        const addData = (val) => {
            result.push(val)
            count ++
            if(count === promises.length){
                resolve(result)
            }
        }

        promises.forEach((promise) => {
            if(item instanceof Promise){
                promise.then(res=> {
                    addData(res)
                }, err => {
                    reject(err)
                })
            } else {
                addData(promise)
            }
        }
    })
}


function race(promises){
    return new Promise((resolve,reject) => {
        promises.forEach((promise)=> {
            if(promise instanceof Promise){
                promise().then(res => {
                    resolve(res)
                }, err => reject(err))
            } else {
                resolve(promise)
            }
        })
    })
}

function allSettled(promises){
    let result = []
    let count = 0
    return new Promise((resolve) => {
        const addData = (status,index,res) => {
            result[index] = {status,res}
            count ++
            if(count === promises.length){
                resolve(result)
            }
        }

        promises.forEach((promise)=> {
            if(promise instanceof Promise){
                promise.then(res => {
                    addData('fulfilled',index, res)
                },err => addData('rejected',index,err))
            } else {
                addData('fulfilled', index, promise)
            }
        })
    })
}

function any(promises) {
    let reason = []
    let count = 0
    return new Promise((resolve, reject) => {
        const addReason = (res,index) => {
            reason[index] = res
            count++
            if(count === promises.length){
                reject(reason)
            }
        }

        promises.forEach((promise)=>{
            if(promise instanceof Promise){
                promise.then(res=> {
                    resolve(res)
                }, err => addReason(err,index))
            } else {
                resolve(promise)
            }
        })
    })
}

class Scheduler {
    constructor(limit){
        this.queue = []
        this.limit = limit
        this.count = 0
    }

    add(time,oder){
        const Task = () => {
            return new Promise((resolve,reject) => {
                setTimeout(()=>{
                    console.log(order)
                    resolve()
                }, time)
            })
        }
        this.queue.push(Task)
    }

    startTask(){
        for(let i = 0; i < this.limit; i++){
            this.request()
        }
    }

    request(){
        if(!this.queue.length || this.count >= this.limit) return
        this.count ++
        this.queue.shift()().then(res=> {
            this.count--
            this.request()
        })
    }
}








